﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Runtime.Serialization;
using System.Runtime.Serialization.Formatters.Binary;

namespace frag_boardgame
{
    /// <summary>
    /// This class holds a table of persistent game statistics,
    /// such as the number of victories for each player.
    /// </summary>
    [DataContract]
    public class StatisticsTable
    {
        /// <summary>
        /// This class holds statistics for a single player
        /// </summary>
        [DataContract]
        public class PlayerStatistics : IComparable<PlayerStatistics>
        {

            [DataMember]
            private string name;

            [DataMember]
            private int timesWon;

            public PlayerStatistics(string name)
            {
                this.name = name;
            }

            /// <summary>
            /// The player's name
            /// </summary>
            public string Name
            {
                get { return name; }
            }

            /// <summary>
            /// The number of times the player has won the game
            /// </summary>
            public int TimesWon
            {
                get { return timesWon; }
                set { timesWon = value; }
            }


            // override object.Equals
            public override bool Equals(object obj)
            {
                PlayerStatistics s = obj as PlayerStatistics;
                if (s == null) return false;

                return Equals(s.name, name) &&
                    Equals(s.timesWon, timesWon);
            }

            // override object.GetHashCode
            public override int GetHashCode()
            {
                return name.GetHashCode() ^ timesWon.GetHashCode();
            }

            #region IComparable<PlayerStatistics> Members

            public int CompareTo(PlayerStatistics other)
            {
                return timesWon.CompareTo(other.timesWon);
            }

            #endregion
        }

        [DataMember]
        Dictionary<string, PlayerStatistics> playerStatsDict;

        public StatisticsTable()
        {
            playerStatsDict = new Dictionary<string, PlayerStatistics>();
        }

        /// <summary>
        /// Add a victory to the given player's statistics
        /// </summary>
        /// <param name="playerName"></param>
        public void AddPlayerVictory(string playerName)
        {
            if (playerStatsDict.ContainsKey(playerName))
            {
                playerStatsDict[playerName].TimesWon += 1;
            }
            else
            {
                PlayerStatistics ps = new PlayerStatistics(playerName);
                ps.TimesWon = 1;
                playerStatsDict[playerName] = ps;
            }
        }

        /// <summary>
        /// Return the player statistics, if they exist
        /// </summary>
        /// <param name="playerName"></param>
        /// <returns></returns>
        public PlayerStatistics GetPlayerStatistics(string playerName)
        {
            if (playerStatsDict.ContainsKey(playerName))
            {
                return playerStatsDict[playerName];
            }
            else
            {
                return null;
            }
        }


        // override object.Equals
        public override bool Equals(object obj)
        {
            StatisticsTable s = obj as StatisticsTable;
            if (s == null) return false;

            // Dictionary can't be compared with Equals(), need to compare manually
            if (s.playerStatsDict.Count != playerStatsDict.Count)
            {
                return false;
            }

            // Check that one dictionary is contained entirely in the other one. Since they are the same size, this is enough.
            foreach (KeyValuePair<string, PlayerStatistics> kvp in s.playerStatsDict) {
                if (!(playerStatsDict.ContainsKey(kvp.Key) && Equals(playerStatsDict[kvp.Key], kvp.Value)))
                {
                    return false;
                }
            }

            return true;
        }

        public override int GetHashCode()
        {
            return playerStatsDict.GetHashCode();
        }

        #region Save and Load

        public void Save(System.IO.Stream stream)
        {
            DataContractSerializer ser = new DataContractSerializer(typeof(StatisticsTable));
            ser.WriteObject(stream, this);
        }

        public static StatisticsTable Load(System.IO.Stream stream)
        {
            DataContractSerializer ser = new DataContractSerializer(typeof(StatisticsTable));
            StatisticsTable table = (StatisticsTable)ser.ReadObject(stream);

            return table;
        }

        #endregion


        public ICollection<PlayerStatistics> GetAllPlayerStatistics()
        {
            List<PlayerStatistics> pls = new List<PlayerStatistics>(playerStatsDict.Values);
            pls.Sort();
            pls.Reverse();
            return pls;
        }

    }
}
